/*
** parse.c for ktrace in /home/matt/Desktop/ensuitetrace
** 
** Made by mathieu1 lornac
** Login   <lornac_a@epitech.net>
** 
** Started on  Thu Dec  9 13:54:43 2010 mathieu1 lornac
** Last update Tue Dec 21 20:34:13 2010 mathieu1 lornac
*/

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <sys/ktrace.h>
#include <unistd.h>

#include "parse.h"

extern int optind;
extern char *optarg;

/*
 * Initialises the structure which handles the ktrace arguments
 */
void		init_args(t_args *args)
{
  args->filename = strdup(DEFAULT_FILENAME);
  args->open_flags = O_WRONLY | O_TRUNC | O_CREAT | O_NONBLOCK;
  args->process_name = 0;
  args->pid = 0;
  args->args_to_skip = 0;
  args->tr_ops = 0;
  args->tr_points = KTRFAC_SYSCALL | KTRFAC_SYSRET |
    KTRFAC_NAMEI | KTRFAC_GENIO | KTRFAC_PSIG | KTRFAC_USER
    | KTRFAC_STRUCT | KTRFAC_SYSCTL;
  args->clear = 0;
}

/*
 * Sets the pid process to trace
 * Checks if the option is only specified once
 */
void		pid_set(t_args *args, char ch, int *first)
{
  if (!*first)
    {
      if (ch == 'p')
	args->pid = atoi(optarg);
      else
	args->pid = -atoi(optarg);
      if (!args->pid)
	{
	  printf("Incorrect pid or gid given\n");
	  free(args);
	  exit(1);
	}
    }
  else
    {
      printf("Only one of the p or g option can be activated or C option activated\n");
      free(args);
      exit(1);
    }
  *first = 1;
}

/*
 * Parses the traces arguments of the option -t
 */
void		parse_trace_points(t_args *args)
{
  int		i = strlen(optarg);

  args->tr_points = KTRFAC_SYSRET;
  while (i--)
    {
      switch (optarg[i])
	{
	case 'c':
	  args->tr_points |= KTRFAC_SYSCALL;
	  break;
	case 'n':
	  args->tr_points |= KTRFAC_NAMEI;
	  break;
	case 'i':
	  args->tr_points |= KTRFAC_GENIO;
	  break;
	case 's':
	  args->tr_points |= KTRFAC_PSIG;
	  break;
	case 't':
	  args->tr_points |= KTRFAC_STRUCT;
	  break;
	case 'u':
	  args->tr_points |= KTRFAC_USER;
	  break;
	case 'w':
	  args->tr_points |= KTRFAC_CSW;
	  break;
	case 'y':
	  args->tr_points |= KTRFAC_NAMEI;
	  break;
	case '+':
	  args->tr_points = KTRFAC_SYSCALL | KTRFAC_NAMEI | KTRFAC_GENIO |
	    KTRFAC_PSIG | KTRFAC_USER | KTRFAC_STRUCT;
	  break;
	default:
	  {
	    free(args);
	    printf("Tracepoints accepted: cnistuwy+\n");
	    exit(1);
	  }
	}
    }
}

/*
 * Parses the arguments given to the command line
 */
t_args		*parse_args(int ac, char ** av)
{
  char		ch;
  t_args	*args;
  int		first;

  first = 0;
  args = malloc(sizeof(*args));
  init_args(args);
  while ((ch = getopt(ac, av, OPT_STRING)) != -1)
    {
      switch (ch)
	{
	case 'a':
	  args->open_flags =  O_WRONLY | O_APPEND | O_CREAT | O_NONBLOCK;
	  break;
	case 'd':
	  args->tr_ops |= KTRFLAG_DESCEND;
	  break;
	case 'f':
	  args->filename = optarg;
	  break;
	case 'i':
	  args->tr_points |= KTRFAC_INHERIT;
	  break;
	case 'p':
	  pid_set(args, ch, &first);
	  break;
	case 'g':
	  pid_set(args, ch, &first);
	  break;
	case 'c':
	  args->clear = 1;
	  break;
	case 'C':
	  args->clear = 2;
	  if (first)
	    {
	      printf("C option incompatible with p or g option");
	      free(args);
	      return 0;
	    }
	      first = 1;
	  break;
	case 't':
	  parse_trace_points(args);
	  break;
	default :
	  free(args);
	  return 0;
	}
    }
  args->args_to_skip = optind;
  return args;
}
